// /common/socket.js
class SocketService {
  constructor() {
    this.socketTask = null;
    this.url = '';
    this.token = '';
    this.status = 'CLOSED'; // 'CLOSED' | 'CONNECTING' | 'OPEN'

    // 重连相关
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 10;
    this.reconnectDelay = 3000; // 基础重连间隔
    this.lockReconnect = false;
    this.isManualClose = false;

    // 心跳相关
    this.heartbeatInterval = 30000; // 30s
    this.heartbeatTimer = null;
    this.heartbeatMsg = { type: 'PING' };

    // 消息监听者（聊天页面 / 其他页面）
    this.listeners = new Set();
  }

  /**
   * 初始化配置，一般在 App.vue onLaunch 调一次
   */
  init(options = {}) {
    this.url = options.url || this.url;
    this.token = options.token || this.token;
    if (!this.url) {
      console.error('[SocketService] WebSocket url 未配置');
      uni.showToast({ title: 'WS: url未配置', icon: 'none' });
      return;
    }
    this.isManualClose = false;
    console.log('[SocketService] init 调用, url:', this.url);
    uni.showToast({ title: 'WS: init调用', icon: 'none', duration: 1500 });
    this.connect();
  }

  /**
   * 建立连接
   */
  connect() {
    if (!this.url) {
      console.error('[SocketService] 请先调用 init 设置 url');
      return;
    }
    if (this.status === 'OPEN' || this.status === 'CONNECTING') {
      console.log('[SocketService] 已经在连接中或已连接');
      return;
    }

    console.log('[SocketService] 开始连接 =>', this.url);
    uni.showToast({ title: 'WS: 开始连接', icon: 'none', duration: 1500 });
    this.status = 'CONNECTING';

    const header = {};
    if (this.token) {
      header['Authorization'] = `Bearer ${this.token}`;
    }

    this.socketTask = uni.connectSocket({
      url: this.url,
      header,
      // #ifdef MP-WEIXIN
      // protocols: ['protocol1'], // 需要的话可以配置
      // #endif
      success: () => {
        console.log('[SocketService] connectSocket 调用成功');
      },
      fail: (err) => {
        console.error('[SocketService] connectSocket 调用失败', err);
        uni.showModal({
          title: 'connectSocket失败',
          content: JSON.stringify(err),
          showCancel: false
        });
        this.status = 'CLOSED';
        this._reconnect();
      }
    });

    // 检查 socketTask 是否有效
    if (!this.socketTask) {
      uni.showModal({
        title: '错误',
        content: 'socketTask 为空，URL: ' + this.url,
        showCancel: false
      });
      return;
    }

    // 监听事件
    this.socketTask.onOpen(this._handleOpen.bind(this));
    this.socketTask.onMessage(this._handleMessage.bind(this));
    this.socketTask.onError(this._handleError.bind(this));
    this.socketTask.onClose(this._handleClose.bind(this));
  }

  _handleOpen(res) {
    console.log('[SocketService] WebSocket 已打开', res);
    uni.showToast({ title: 'WS: 连接成功', icon: 'success', duration: 1500 });
    this.status = 'OPEN';
    this.reconnectAttempts = 0;
    this._startHeartbeat();
  }

  _handleMessage(res) {
    let data = res.data;

    try {
      data = typeof data === 'string' ? JSON.parse(data) : data;
    } catch (e) {
      // 非 JSON，原样给出去
    }

    // 分发给所有监听者
    this.listeners.forEach((fn) => {
      try {
        fn(data);
      } catch (e) {
        console.error('[SocketService] 消息监听回调错误', e);
      }
    });
  }

  _handleError(err) {
    console.error('[SocketService] WebSocket 错误', err);
    // 显示详细错误信息
    uni.showModal({
      title: 'WS连接错误',
      content: JSON.stringify(err),
      showCancel: false
    });
    // 出错也走 close 流程，reconnect 在 close 里统一处理
  }

  _handleClose(res) {
    console.warn('[SocketService] WebSocket 已关闭', res);
    // 显示关闭原因
    uni.showModal({
      title: 'WS连接关闭',
      content: `code: ${res.code}, reason: ${res.reason || '无'}`,
      showCancel: false
    });
    this.status = 'CLOSED';
    this._clearHeartbeat();

    if (!this.isManualClose) {
      this._reconnect();
    }
  }

  /**
   * 发送消息
   */
  send(data) {
    if (this.status !== 'OPEN') {
      console.warn('[SocketService] 当前未连接，消息丢弃或可考虑缓存队列', data);
      return;
    }

    const payload = typeof data === 'string' ? data : JSON.stringify(data);
    this.socketTask.send({
      data: payload,
      fail: (err) => {
        console.error('[SocketService] 发送失败', err, data);
      }
    });
  }

  /**
   * 主动关闭连接（例如退出登录）
   */
  close() {
    this.isManualClose = true;
    this._clearHeartbeat();
    if (this.socketTask) {
      this.socketTask.close({
        code: 1000,
        reason: '主动关闭'
      });
      this.socketTask = null;
    }
  }

  /**
   * 重连逻辑，带简单退避
   */
  _reconnect() {
    if (this.isManualClose) return;
    if (this.lockReconnect) return;
    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.error('[SocketService] 重连次数已达上限，不再重连');
      return;
    }

    this.lockReconnect = true;
    this.reconnectAttempts += 1;
    const delay = this.reconnectDelay * this.reconnectAttempts; // 简单线性退避

    console.log(`[SocketService] ${delay}ms 后尝试第 ${this.reconnectAttempts} 次重连`);

    setTimeout(() => {
      this.lockReconnect = false;
      this.connect();
    }, delay);
  }

  /**
   * 启动心跳
   */
  _startHeartbeat() {
    this._clearHeartbeat();
    if (!this.heartbeatInterval) return;

    this.heartbeatTimer = setInterval(() => {
      if (this.status === 'OPEN') {
        this.send(this.heartbeatMsg);
      }
    }, this.heartbeatInterval);
  }

  _clearHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  /**
   * 添加消息监听（聊天界面 / 其他业务页面调用）
   */
  addMessageListener(fn) {
    if (typeof fn === 'function') {
      this.listeners.add(fn);
    }
  }

  /**
   * 移除消息监听
   */
  removeMessageListener(fn) {
    this.listeners.delete(fn);
  }
}

// 导出单例
const socketService = new SocketService();
export default socketService;
